package net.zoneland.knowledge.service.impl;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.google.common.collect.Lists;
import net.zoneland.knowledge.config.EsConfig;
import net.zoneland.knowledge.constant.FieldConstant;
import net.zoneland.knowledge.enums.*;
import net.zoneland.knowledge.utils.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.base.Preconditions;

import net.zoneland.knowledge.cache.RedisCacheUtil;
import net.zoneland.knowledge.config.BizConfig;
import net.zoneland.knowledge.constant.BizConstant;
import net.zoneland.knowledge.dao.ErrorCorrectionFileMapper;
import net.zoneland.knowledge.dao.ErrorCorrectionMapper;
import net.zoneland.knowledge.model.DictItem;
import net.zoneland.knowledge.model.ErrorCorrection;
import net.zoneland.knowledge.model.ErrorCorrectionFile;
import net.zoneland.knowledge.model.EsQuestion;
import net.zoneland.knowledge.model.LoginUserPojo;
import net.zoneland.knowledge.service.DataManageService;
import net.zoneland.knowledge.service.DictItemService;
import net.zoneland.knowledge.service.ErrorCorrectionService;
import net.zoneland.knowledge.service.NotifyService;
import net.zoneland.knowledge.service.RoleService;
import net.zoneland.uniflow.client.TaskObject;
import net.zoneland.uniflow.client.UserInfo;

/**
 * 纠错业务接口实现.
 * @author zmq
 */
@Service
public class ErrorCorrectionServiceImpl implements ErrorCorrectionService {
    /**
     * 日志.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ErrorCorrectionServiceImpl.class);

    /**
     * 逗号.
     */
    private static final String DOUHAO = ",";

    /**
     * 数据接口.
     */
    @Autowired
    private ErrorCorrectionMapper errorCorrectionMapper;
    /**
     * 字典业务接口.
     */
    @Autowired
    private DictItemService dictItemService;
    /**
     * 统一通知业务接口.
     */
    @Autowired
    private NotifyService notifyService;
    /**
     * 数据管理业务接口.
     */
    @Autowired
    private DataManageService dataManageService;

    /**
     * 纠错文件数据接口.
     */
    @Autowired
    private ErrorCorrectionFileMapper errorCorrectionFileMapper;

    /**
     * 角色接口.
     */
    @Autowired
    private RoleService roleService;
    /**
     * 业务配置接口.
     */
    @Autowired
    private BizConfig bizConfig;
    /**
     * redis缓存工具类.
     */
    @Autowired
    private RedisCacheUtil redisCacheUtil;

    @Autowired
    private EsConfig esConfig;

    /**
     * 添加纠错信息.
     *
     * @param desc    描述
     * @param esQuestionId es题库id
     * @param curUser 当前用户
     * @return 纠错信息的id
     */
    private String addErrorCorrectionForId(final String desc, final String esQuestionId,
                                     final LoginUserPojo curUser) {
        String id = "";
        try {
            Preconditions.checkArgument(StringUtils.isNotBlank(desc), "纠错描述不能为空！");
            Preconditions.checkArgument(StringUtils.isNotBlank(esQuestionId), "纠错信息id不能为空！");
            Preconditions.checkNotNull(curUser, "当前用户信息不能为空！");
            ErrorCorrection errorCorrection = this.buildErrorCorrection(desc, esQuestionId, curUser);
            id = errorCorrection.getId();
            EsQuestion es = dataManageService.getById(esQuestionId);
            Preconditions.checkNotNull(es, "当前esId对应题库不存在，无法纠错！");
            errorCorrection.setCorrectType(es.getCategory());
            // FIXME 插入纠错
//            if (CategoryEnum.RHW == es.getCategory()) {
//                errorCorrection.setCorrectType(CorrectTypeEnum.RHW);
//                correctRhw(errorCorrection, curUser, es);
//            } else {
//                errorCorrection.setCorrectType(CorrectTypeEnum.RHC_PERSON);
//                correctRhcPerson(errorCorrection, curUser, es);
//            }
        } catch (Exception e) {
            String message = "添加纠错失败！";
            LOGGER.error(message, e);
            throw new IllegalStateException(message, e);
        }
        return id;
    }

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public void addErrorCorrection(final String desc, final String esQuestionId,
                                   final LoginUserPojo curUser, final List<MultipartFile> files) {
        String id = addErrorCorrectionForId(desc, esQuestionId, curUser);
        if (CollectionUtils.isEmpty(files) || StringUtils.isBlank(id)) {
            return;
        }
        files.forEach(multipartFile -> {
            try {
                byte[] bytes = multipartFile.getBytes();
                String fileName = multipartFile.getOriginalFilename();
                String[] split = fileName.split("\\\\");
                fileName = split[split.length-1];
                ErrorCorrectionFile newFile = getNewFile(id, fileName, bytes);
                errorCorrectionFileMapper.insert(newFile);
            } catch (Exception e) {
                String message = "附件上传失败。";
                LOGGER.error(message, e);
                throw new IllegalStateException(message, e);
            }
        });
    }

    /**
     * 创建附件对象.
     * @param correctionId 关联纠错对象的id
     * @param fileName 文件名称
     * @param bytes 附件
     * @return 附件对象
     */
    private ErrorCorrectionFile getNewFile(final String correctionId, final String fileName, final byte[] bytes) {
        ErrorCorrectionFile errorCorrectionFile = new ErrorCorrectionFile();
        errorCorrectionFile.setId(UUID.randomUUID().toString());
        errorCorrectionFile.setCorrectionId(correctionId);
        errorCorrectionFile.setFileName(fileName);
        errorCorrectionFile.setErrorFile(bytes);
        return errorCorrectionFile;
    }

    /**
     * 发送邮件提醒.
     * @param errorCorrection 纠错
     * @param tasks 流程任务信息
     * @param title 标题
     */
    private void notifyHandlers(final ErrorCorrection errorCorrection, final TaskObject[] tasks,
                                final String title) {
//        Arrays.stream(tasks).filter(it -> Objects.nonNull(it.getHandler())).forEach(task -> {
//            try {
//                notifyService.notifyByEmail(task.getHandler().getUserId(), "智慧人力共享赋能中心（HR SEC）待办任务--" + title,
//                    EmailContentUtils.buildEmailContent(errorCorrection, task, errorCorrectUrlPrefix));
//            } catch (UnsupportedEncodingException e) {
//                LOGGER.error("纠错流程发送邮件提醒失败！tiid:{}", task.getTiid(), e);
//            }
//        });
    }

    /**
     * 构造纠错对象.
     * @param desc 描述
     * @param esQuestionId 问题id
     * @param curUser 当前用户
     * @return 纠错对象
     */
    private ErrorCorrection buildErrorCorrection(final String desc, final String esQuestionId,
                                                 final LoginUserPojo curUser) {
        ErrorCorrection errorCorrection = new ErrorCorrection();
        errorCorrection.setEsQuestionId(esQuestionId);
        errorCorrection.setDescription(desc);
        errorCorrection.setCreateTime(Calendar.getInstance().getTime());
        errorCorrection.setUpdateTime(errorCorrection.getCreateTime());
        errorCorrection.setCreatorUid(curUser.getUserID());
        errorCorrection.setCreatorName(curUser.getUserName());
        errorCorrection.setId(UUID.randomUUID().toString());
        return errorCorrection;
    }


    /**
     * 对RHW信息进行纠错.
     * @param errorCorrection 纠错对象
     * @param curUser 当前用户
     */
    private void correctRhw(final ErrorCorrection errorCorrection, final LoginUserPojo curUser, final EsQuestion esQuestion) throws Exception {
        //FIXME
        //        // 发送邮件
//        String valueByCityId = QaBankCmpDnEnum.getValueByCityId(esQuestion.getFlag());
//        // 如果是通用题库纠错，则需要去找省公司的题库管理员
//        if (StringUtils.equals(valueByCityId, QaBankCmpDnEnum.COMMONZMCC.getValue())) {
//            valueByCityId = QaBankCmpDnEnum.ZMCC.getValue();
//        }
//        List<UserInfo> handlers = getBankManager(valueByCityId);
//        if (CollectionUtils.isEmpty(handlers)) {
//            //当前未配置管理员
//            LOGGER.error("当前未配置题库管理员，flag->{}", esQuestion.getFlag());
//            errorCorrection.setStatus(CorrectStatusEnum.DRAFT);
//        } else {
//            UserInfo[] handlerArr = handlers.toArray(new UserInfo[0]);
//            String applyId = String.format(BizConstant.EC_RHW_APPLY_ID, errorCorrection.getId());
//            String applyTitle = String.format(BizConstant.EC_RHW_APPLY_TITLE, esQuestion.getLevel1Title(), esQuestion.getLevel2Title());
//            TaskObject[] tasks = this.uniflowService.startProcess(BizConstant.EC_RHC_PERSON_BIZ_PROCESS,
//                new UserInfo(curUser.getUserID(), curUser.getUserName(), curUser.getDepartmentDN(), curUser.getDeptName()),
//                applyId,
//                applyTitle,
//                true, handlerArr, null);
//            errorCorrection.setStatus(CorrectStatusEnum.DEALING);
//            errorCorrection.setHandlerUid(handlers.stream().map(UserInfo::getUserId).collect(Collectors.joining(DOUHAO)));
//            errorCorrection.setHandlerName(handlers.stream().map(UserInfo::getUserName).collect(Collectors.joining(DOUHAO)));
//            // 发送通知提醒
//            this.notifyHandlers(errorCorrection, tasks, "慧问题库纠错");
//        }
//        this.errorCorrectionMapper.insert(errorCorrection);
    }

    /**
     * 获取公司对应的题库管理员.
     * @param companyDn 公司dn
     * @return 管理员uid
     */
    private List<UserInfo> getBankManager(final String companyDn) {
        return BizCacheUtils.getRoleUsers(companyDn, bizConfig.getHrAdminRole(),
            BizConstant.HR_ADMIN_CACHE_KEY, redisCacheUtil, roleService);
    }
}
